package com.bridgeintelligent.tag.scene.service;

import com.bridgeintelligent.tag.scene.api.ISceneCatalogService;
import com.bridgeintelligent.tag.scene.api.dto.SceneDto;
import com.bridgeintelligent.tag.scene.api.entity.SceneCatalog;
import com.bridgeintelligent.tag.scene.api.vo.SceneCatalogVO;
import com.bridgeintelligent.tag.scene.api.vo.SceneVO;
import com.bridgeintelligent.tag.scene.mapper.SceneCatalogMapper;
import com.bridgeintelligent.tag.scene.mapper.SceneMapper;
import com.bridgeintelligent.tag.webserver.dim.mgmt.api.IdWorker;
import lombok.AllArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @description
 * @author: grp 2021-01-10 20:10
 **/
@Service
@AllArgsConstructor
public class SceneCatalogServiceImpl implements ISceneCatalogService {

    private SceneCatalogMapper sceneCatalogMapper;
    private SceneMapper sceneMapper;

    @Override
    public List<SceneCatalog> list() {
        List<SceneCatalog> result = sceneCatalogMapper.findCatalogList();
        if(CollectionUtils.isEmpty(result)){
            return new ArrayList<>();
        }
        Map<String, List<SceneCatalog>> sceneListMap = result.stream()
                .collect(Collectors.groupingBy(SceneCatalog::getParentId));
        List<SceneCatalog> list = new ArrayList<>(result.size());
        Map<String, SceneCatalog> sceneMap = result.stream()
                .collect(Collectors.toMap(SceneCatalog::getId, sceneCatalog -> sceneCatalog));
        List<SceneCatalog> parentList = sceneListMap.get("-");
        parentList.forEach(sceneCatalog -> list.add(findVO(sceneListMap, sceneMap, sceneCatalog.getId())));
        parentList.sort(Comparator.comparing(SceneCatalog::getNumber));
        return parentList;
    }

    @Override
    public SceneDto<Object> add(String parentId, String name, Integer number) {
        int result = sceneCatalogMapper.findCatalogNameIsExits(name, parentId);
        if (result > 0) {
            return SceneDto.error("同级目录下目录名重复！");
        }
        String id = IdWorker.nextId();
        int level;
        if (PARENT_ID.equals(parentId)) {
            level = 1;
        } else {
            level = sceneCatalogMapper.findParent(parentId) + 1;
        }
        if (level > 3) {
            return SceneDto.error("只能创建3级目录！");
        }
        sceneCatalogMapper.add(id, name, parentId, findMax(parentId), level);
        return SceneDto.success();
    }

    @Override
    public void update(String id, String parentId, String name, Integer number) {
        SceneCatalog sceneCatalog = sceneCatalogMapper.findById(id);
        updateHandler(sceneCatalog, id, parentId, name, number);
    }

    @Override
    public SceneDto<Object> del(String id) {
        List<SceneCatalog> list = sceneCatalogMapper.findNext(id);
        if (list.isEmpty()) {
            sceneCatalogMapper.del(id);
            return SceneDto.success();
        } else {
            return SceneDto.error("删除失败，此目录有下级目录！");
        }
    }

    @Override
    public List<SceneCatalog> parentList() {
        return sceneCatalogMapper.findParents();
    }

    @Override
    public Map<String, List<SceneVO>> scenes(String type) {
        Map<String, List<SceneVO>> map = new HashMap<>();
        List<SceneCatalog> sceneCatalogs = sceneCatalogMapper.findParents();
        for (SceneCatalog sceneCatalog : sceneCatalogs) {
            List<SceneCatalog> all = new ArrayList<>();
            //获取该目录下的所有子目录
            List<SceneCatalog> subCatalogs = sceneCatalogMapper.findNext(sceneCatalog.getId());
            //查找该目录下的所有场景
            for (SceneCatalog catalog : subCatalogs) {
                all.addAll(sceneCatalogMapper.findNext(catalog.getId()));
            }
            all.add(sceneCatalog);
            all.addAll(subCatalogs);
            List<SceneVO> showList = sceneCatalogMapper.top(all,type);
            map.put(sceneCatalog.getId(),showList);
        }
        List<SceneVO> allList = sceneCatalogMapper.top(new ArrayList<>(),type);
        allList.forEach(e->{
            if(ZERO_FOUR.equals(e.getFunctionType())){
                e.setFunctionId(sceneCatalogMapper.findExploreById(e.getFunctionId())==1?e.getFunctionId():"");
            }
        });
        map.put("all", allList);
        return map;
    }

    @Override
    public List<SceneVO> sceneList(String id) {
        SceneCatalog sceneCatalog = sceneCatalogMapper.findById(id);
        List<SceneCatalog> all = new ArrayList<>();
        List<SceneCatalog> subCatalogs = sceneCatalogMapper.findNext(sceneCatalog.getId());
        for (SceneCatalog catalog : subCatalogs) {
            all.addAll(sceneCatalogMapper.findNext(catalog.getId()));
        }
        all.add(sceneCatalog);
        all.addAll(subCatalogs);
        return sceneCatalogMapper.subScene(all);
    }

    @Override
    public List<SceneCatalogVO> catalogs(String id) {
        List<SceneCatalogVO> result = sceneCatalogMapper.findCatalogVOs();
        Map<String, List<SceneCatalogVO>> sceneListMap = result.stream()
                .collect(Collectors.groupingBy(SceneCatalogVO::getParentId));
        List<SceneCatalogVO> list = new ArrayList<>(result.size());
        Map<String, SceneCatalogVO> sceneMap = result.stream()
                .collect(Collectors.toMap(SceneCatalogVO::getId, sceneCatalog -> sceneCatalog));
        List<SceneCatalogVO> parentList = sceneListMap.get("-");
        SceneVO sceneVO= null;
        if(StringUtils.isNotBlank(id)){
            sceneVO = sceneMapper.findById(id);
        }
        if(parentList==null){
            return null;
        }
        SceneVO finalSceneVO = sceneVO;
        parentList.forEach(sceneCatalog -> list.add(findVO2(sceneListMap, sceneMap, sceneCatalog.getId(), finalSceneVO)));
        parentList.sort(Comparator.comparing(SceneCatalogVO::getNumber));
        return parentList;
    }

    @Override
    public List<SceneCatalogVO> tree() {
        List<SceneCatalogVO> result = sceneCatalogMapper.findCatalogVOs();
        Map<String, List<SceneCatalogVO>> sceneListMap = result.stream()
                .collect(Collectors.groupingBy(SceneCatalogVO::getParentId));
        List<SceneCatalogVO> list = new ArrayList<>(result.size());
        Map<String, SceneCatalogVO> sceneMap = result.stream()
                .collect(Collectors.toMap(SceneCatalogVO::getId, sceneCatalog -> sceneCatalog));
        List<SceneCatalogVO> parentList = sceneListMap.get("-");
        parentList.forEach(sceneCatalog -> list.add(findVO3(sceneListMap, sceneMap, sceneCatalog.getId())));
        parentList.sort(Comparator.comparing(SceneCatalogVO::getNumber));
        return parentList;
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateHandler(SceneCatalog sceneCatalogOld, String id, String parentId, String name, Integer number) {
        boolean isUp = false, isChangePosition = true;
        SceneCatalog sceneCatalog = new SceneCatalog();
        sceneCatalog.setId(id)
                .setParentId(parentId)
                .setName(name)
                .setNumber(number);
        if (null != number && number.equals(sceneCatalogOld.getNumber())) {
            isChangePosition = false;
        }
        if (isChangePosition) {
            SceneCatalog neighbor = sceneCatalogMapper.findByNumber(sceneCatalogOld.getParentId(), number);
            if (neighbor != null) {
                neighbor.setNumber(sceneCatalogOld.getNumber());
                sceneCatalogMapper.update(neighbor);
            }
        }
        sceneCatalogMapper.update(sceneCatalog);
    }

    private int findMax(String parentId) {
        Integer max = sceneCatalogMapper.findMaxNumber(parentId);
        return max == null ? 0 : max + 1;
    }

    private SceneCatalog findVO(Map<String, List<SceneCatalog>> sceneListMap, Map<String, SceneCatalog> sceneMap, String id) {
        SceneCatalog sceneCatalog = sceneMap.get(id);
        List<SceneCatalog> list = sceneListMap.get(sceneCatalog.getId());
        if (null != list) {
            list.sort(Comparator.comparing(SceneCatalog::getNumber));
            list.forEach(sceneCatalog1 -> {
                SceneCatalog catalogVOChirld = findVO(sceneListMap, sceneMap, sceneCatalog1.getId());
                sceneCatalog.getChildren()
                        .add(catalogVOChirld);
            });
        } else {
            return sceneCatalog;
        }
        return sceneCatalog;
    }

    private SceneCatalogVO findVO2(Map<String, List<SceneCatalogVO>> sceneListMap, Map<String, SceneCatalogVO> sceneMap,
                                   String id, SceneVO sceneVO) {
        SceneCatalogVO sceneCatalog = sceneMap.get(id);
        List<SceneCatalogVO> list = sceneListMap.get(sceneCatalog.getId());
        if (null != list) {
            list.sort(Comparator.comparing(SceneCatalogVO::getNumber));
            list.forEach(sceneCatalog1 -> {
                SceneCatalogVO catalogVOChirld = findVO2(sceneListMap, sceneMap, sceneCatalog1.getId(), sceneVO);
                sceneCatalog.getChildren()
                        .add(catalogVOChirld);
            });
        }
        if(sceneVO!=null&&StringUtils.equals(sceneCatalog.getId(),sceneVO.getCatalogId())){
            sceneCatalog.getChildren()
                    .add(sceneVO);
        }
        return sceneCatalog;
    }

    private SceneCatalogVO findVO3(Map<String, List<SceneCatalogVO>> sceneListMap, Map<String, SceneCatalogVO> sceneMap,
                                   String id) {
        SceneCatalogVO sceneCatalog = sceneMap.get(id);
        List<SceneCatalogVO> list = sceneListMap.get(sceneCatalog.getId());
        if (null != list) {
            list.sort(Comparator.comparing(SceneCatalogVO::getNumber));
            list.forEach(sceneCatalog1 -> {
                SceneCatalogVO catalogVOChirld = findVO3(sceneListMap, sceneMap, sceneCatalog1.getId());
                sceneCatalog.getChildren()
                        .add(catalogVOChirld);
            });
        }
        List<SceneVO> sceneVOS = sceneMapper.findByParentId(sceneCatalog.getId());
        if(CollectionUtils.isNotEmpty(sceneVOS)){
            sceneCatalog.getChildren()
                    .addAll(sceneVOS);
        }
        return sceneCatalog;
    }
}
